package www.meng.com.config;


import com.zaxxer.hikari.HikariDataSource;
import org.beetl.core.Context;
import org.beetl.core.Function;
import org.beetl.sql.core.*;
import org.beetl.sql.core.db.MySqlStyle;
import org.beetl.sql.core.engine.template.BeetlTemplateEngine;
import org.beetl.sql.ext.DebugInterceptor;
import www.meng.com.entity.PeopleEntity;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <ui>
 *     <li>
 *      演示多数据源操作中的ConditionalSQLManager，按照条件决定使用哪个SQLManager
 *      ConditionalSQLManager.decide方法决定使用哪个SQLManager，
 *      decide默认会读取目标对象的TargetSQLManager注解来决定，SQLManager的有些api参数没有目标对象，则使用默认SQLManager
 *     </li>
 *     <li>
 *         演示user分表操作，动态表名实现分表
 *     </li>
 *     <li>
 *         演示user分库操作，根据条件决定数据访问哪个数据库，使用了{@link ConditionalConnectionSource}
 *     </li>
 * </ui>

 *
 *
 * 注意：分库分表最好使用中间件
 * @author xiandafu
 */

public class S6MoreDatabase {

    public S6MoreDatabase() {
    }

    public static void main(String[] args) throws Exception {

        S6MoreDatabase moreSource = new S6MoreDatabase();
        moreSource.multipleDataBaseAndTables();
    }


    /**
     * 分库分布表操作，同{@link #multipleTables()} 方法，但增加如果id超过一定限额，走另外一个数据库
     * 核心还是需要定义一个分库分表逻辑
     * @see TableAndDataBaseChoice
     */
    public void multipleDataBaseAndTables(){
        SQLManager sqlManager = getSQLManager4MultipleDatBase();
        List<PeopleEntity> all = sqlManager.all(PeopleEntity.class);
        for (PeopleEntity peopleEntity : all) {
            System.out.println("姓名： " + peopleEntity.getpName());
        }
    }

    static String dsName = "cs2";
    /**
     * 分库选择逻辑，用户自由实现分表分库逻辑，
     */
    public static  class TableAndDataBaseChoice{
        public String getTableName(ExecuteContext executeContext,String tableName){

            System.out.println("++++++++ TableName: " + tableName);
            executeContext.setContextPara(FLAG, dsName);
            return tableName;
        }
    }

    private static final String FLAG ="connectionSource";
    protected static SQLManager getSQLManager4MultipleDatBase(){
        //为了测试方便，假设指向同一个数据库

        HikariDataSource ds1 = new HikariDataSource();
        ds1.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/t-beelsql3?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");
        ds1.setUsername("root");
        ds1.setPassword("root");
        ds1.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ConnectionSource cs1 = ConnectionSourceHelper.getSingle(ds1);

        HikariDataSource ds2 = new HikariDataSource();
        ds2.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/t-beelsql4?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");
        ds2.setUsername("root");
        ds2.setPassword("root");
        ds2.setDriverClassName("com.mysql.cj.jdbc.Driver");

        ConnectionSource cs2 = ConnectionSourceHelper.getSingle(ds2);

        Map<String,ConnectionSource>  datas = new HashMap<>();
        datas.put("cs1",cs1);
        datas.put("cs2",cs2);

        // 配置策略
        ConditionalConnectionSource.Policy policy = new ConditionalConnectionSource.Policy() {
            @Override
            public String getConnectionSourceName(ExecuteContext ctx, boolean isUpdate) {
                String name = (String)ctx.getContextPara(FLAG);
                if(name!=null){
                    return name;
                }else{
                    // 如果没有设置，则返回一个默认库
                    return "cs1";
                }
            }
            @Override
            public String getMasterName() {
                return "cs1";
            }
        };

       ConditionalConnectionSource ds  = new ConditionalConnectionSource(policy,datas);
        // 初始化sqlManager，使用ConditionalConnectionSource
        SQLManagerBuilder builder = new SQLManagerBuilder(ds);
        builder.setNc(new UnderlinedNameConversion());
        builder.setInters(new Interceptor[]{new DebugInterceptor()});
        builder.setDbStyle(new MySqlStyle());
        SQLManager sqlManager = builder.build();
        // 申明一个虚表 "${toTable('user',id)}"，实际上是user表
//        sqlManager.addVirtualTable("sys_user",USER_TABLE);
        BeetlTemplateEngine templateEngine = (BeetlTemplateEngine)sqlManager.getSqlTemplateEngine();
        // 注册一个方法来实现映射到多表的逻辑
        templateEngine.getBeetl().getGroupTemplate().registerFunction("toTable", new Function(){

            @Override
            public Object call(Object[] paras, Context ctx) {
                String tableName = (String)paras[0];
                ExecuteContext executeContext = (ExecuteContext)ctx.getGlobal(ExecuteContext.NAME);
                //使用分库逻辑
                TableAndDataBaseChoice choice = new TableAndDataBaseChoice();
                return choice.getTableName(executeContext,tableName);
            }
        });

        return sqlManager;

    }

}
